package com.hscm.boss.mvc.service.impl;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hscm.boss.common.client.RedisClient;
import com.hscm.boss.common.consants.KeyConstant;
import com.hscm.boss.common.enums.PublicStatus;
import com.hscm.boss.common.enums.ResponseCode;
import com.hscm.boss.common.events.model.NoticeUserPaymentEvent;
import com.hscm.boss.common.exception.BossException;
import com.hscm.boss.common.utils.NoUtil;
import com.hscm.boss.common.utils.mails.model.MailProperties;
import com.hscm.boss.dao.entity.PayProduct;
import com.hscm.boss.dao.entity.UserInfo;
import com.hscm.boss.dao.entity.UserPayConfig;
import com.hscm.boss.dao.entity.UserPayInfo;
import com.hscm.boss.dao.mapper.*;
import com.hscm.boss.mvc.model.from.config.KqConfig;
import com.hscm.boss.mvc.model.from.config.UserPayConfigForm;
import com.hscm.boss.mvc.model.from.config.WxConfig;
import com.hscm.boss.mvc.service.UserConfigService;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

@Service
public class UserConfigServiceImpl implements UserConfigService {

    @Value("${spring.mail.username}")  //将邮件的发送方注入进来
    private String mailFrom;

    @Resource
    private UserPayConfigMapper payConfigMapper;

    @Resource
    private UserInfoMapper userInfoMapper;

    @Resource
    private UserPayInfoMapper payInfoMapper;

    @Resource
    private PayProductMapper productMapper;

    @Resource
    private PayWayMapper payWayMapper;

    @Resource
    private ApplicationEventPublisher applicationEventPublisher;

    @Resource
    private RedisClient redisClient;


    @Override
    public IPage<UserPayConfig> pageList(Integer pageNo, Integer pageSize) {
        QueryWrapper<UserPayConfig> wrapper = new QueryWrapper<>();
        wrapper.orderByAsc("user_no", "pay_product_code");

        return payConfigMapper.selectPage(Page.of(pageNo, pageSize), wrapper);
    }

    @Override
    public List<UserInfo> matchShopName(String shopName) {

        QueryWrapper<UserInfo> wrapper = new QueryWrapper<>();
        wrapper.like("shop_name", shopName)
                .orderByAsc("shop_name");

        return userInfoMapper.selectList(wrapper);
    }


    //本业务方式需要操作两个表
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void createUserPayConfig(UserPayConfigForm userPayConfigForm) {
        //1.确保 user_pay_config表中的 user_no 和 pay_product_code 是唯一的
        QueryWrapper<UserPayConfig> wrapper = new QueryWrapper<>();
        wrapper.eq("user_no", userPayConfigForm.getUserNo())
                .eq("pay_product_code", userPayConfigForm.getProductCode());
        UserPayConfig userPayConfig = payConfigMapper.selectOne(wrapper);
        if (userPayConfig != null) {//用户的支付配置已经存在
            throw new BossException(ResponseCode.PAYMENT_USER_PRODUCT_EXISTS);
        }

        //2.1检查支付产品  因为前端是输框的形式可能被被修改 所以需要验证
        PayProduct product = productMapper.selectOne(new QueryWrapper<PayProduct>()
                .eq("product_code", userPayConfigForm.getProductCode()));
        if (product == null) {//没有这个产品
            throw new BossException(ResponseCode.PAYMENT_CODE_EXISTS);
        }
        // 如果没有抛出异常 product.getProductName() 就一定是正确的
        userPayConfigForm.setProductName(product.getProductName());


        //2.2检查用户的信息  因为前端是输框的形式可能被被修改 所以需要验证
        UserInfo userInfo = userInfoMapper.selectOne(new QueryWrapper<UserInfo>()
                .eq("user_no", userPayConfigForm.getUserNo()));

        if (userInfo == null) {//没有这会用户
            throw new BossException(ResponseCode.USER_NOT_EXISTS);
        }
        // 如果没有抛出异常 userInfo.getShopName() 就一定是正确的
        userPayConfigForm.setShopName(userInfo.getShopName());


        //3 创建配置信息
        userPayConfig = new UserPayConfig();
        userPayConfig.setId(NoUtil.getUUID());
        userPayConfig.setUserNo(userPayConfigForm.getUserNo());
        userPayConfig.setShopName(userPayConfigForm.getShopName());
        userPayConfig.setPayProductCode(userPayConfigForm.getProductCode());
        userPayConfig.setPayProductName(userPayConfigForm.getProductName());
        userPayConfig.setRiskDay(userPayConfigForm.getRiskDay());
        userPayConfig.setAppKey(NoUtil.getUUID());
        userPayConfig.setAppSecret(NoUtil.getUUID()); //密钥
        userPayConfig.setMerchantServerIp(userPayConfigForm.getIpList());//白名单
        //自动结算
        userPayConfig.setAutoSett("autoYes".equals(userPayConfigForm.getAutoSett()) ? "YES" : "NO");
        userPayConfig.setRemark("创建支付的配置");
        userPayConfig.setEditTime(new Date());
        userPayConfig.setStatus(PublicStatus.ENABLE.name());
        payConfigMapper.insert(userPayConfig);


        //查询支付产品的包含的支付方式列表
        Map<String, String> paymentInfoMap = new HashMap<>();
        List<String> payWayCodeList = payWayMapper.selectPayWayList(userPayConfigForm.getProductCode());

        if (payWayCodeList.size() == 0) {//说明没有配置支付方式
            throw new BossException(ResponseCode.PAYMENT_PRODUCT_PAYWAY_NONE);
        }

        //payWayCode 只有三种值ALIPAY WEIXIN KUAIQIAN
        for (String payWayCode : payWayCodeList) {
            //支付方式需要user_pay_info表 存的是第三方的配置信息
            /*提取的公共的需要设置的参数的信息*/
            UserPayInfo payInfo = new UserPayInfo();
            payInfo.setId(NoUtil.getUUID());
            payInfo.setPayProductCode(userPayConfigForm.getProductCode());
            payInfo.setUserNo(userPayConfigForm.getUserNo());
            payInfo.setShopName(userPayConfigForm.getShopName());
            payInfo.setEditTime(new Date());
            payInfo.setStatus(PublicStatus.ENABLE.name());

            if ("KUAIQIAN".equals(payWayCode)) {
                KqConfig kqConfig = userPayConfigForm.getKqConfig();
                //快钱不为空 且商户号、私钥、公钥、查询秘钥不为空
                if (kqConfig != null
                        && StrUtil.isNotBlank(kqConfig.getMerchId())
                        && StrUtil.isNotBlank(kqConfig.getPrivateFile())
                        && StrUtil.isNotBlank(kqConfig.getPublicFile())
                        && StrUtil.isNotBlank(kqConfig.getQueryKey())) {
                    //以上条件都满足把块钱的信息写入UserPay
                    payInfo.setPayWayCode("KUAIQIAN");
                    payInfo.setPayWayName("快钱");
                    payInfo.setPayConfig(JSONUtil.toJsonStr(kqConfig));
                    payInfo.setRemark("快钱的支付方式");
                    //添加第三方支付的信息
                    payInfoMapper.insert(payInfo);

                    paymentInfoMap.put("KUAIQIAN", payInfo.getPayConfig());
                } else {
                    throw new BossException(ResponseCode.PAYMENT_USER_PAYINFO_NONE);
                }
            } else if ("WEIXIN".equals(payWayCode)) {
                //根据提交的数据有什么 ，就存什么
                WxConfig wxConfig = userPayConfigForm.getWxConfig();
                //微信不能对象 微信号、商家号 不能为空
                if (wxConfig != null && StrUtil.isNotBlank(wxConfig.getAppId()) && StrUtil.isNotBlank(wxConfig.getMerchId())) {
                    payInfo.setPayWayCode("WEIXIN");
                    payInfo.setPayWayName("微信");
                    payInfo.setPayConfig(JSONUtil.toJsonStr(wxConfig));
                    payInfo.setRemark("微信的支付方式");
                    //添加第三方支付的信息
                    payInfoMapper.insert(payInfo);

                    paymentInfoMap.put("WEIXIN", payInfo.getPayConfig());
                } else {
                    throw new BossException(ResponseCode.PAYMENT_USER_PAYINFO_NONE);
                }
            }
        }

        //缓存 商户 配置的支付产品到 redis中
        //还有第三方支付方式  在上面的方法中
        paymentInfoMap.put("appKey", userPayConfig.getAppKey());
        paymentInfoMap.put("appSecret", userPayConfig.getAppSecret());
        paymentInfoMap.put("productName", userPayConfig.getPayProductName());
        paymentInfoMap.put("ipList", userPayConfig.getMerchantServerIp());

        //缓存到Redis中
        setCachePayConfig(userPayConfig.getUserNo(), userPayConfig.getPayProductCode(), paymentInfoMap);

        //通过邮件将配置信息发送给商家
        sendNoticeMail(userPayConfig, userInfo, payWayCodeList);

    }

    private void setCachePayConfig(String userNo, String productNo, Map<String, String> userPayMap) {
        String key = KeyConstant.USER_PRODUCT_CONFIG + userNo + ":" + productNo;
        redisClient.setHashMap(key, userPayMap);
    }

    private void sendNoticeMail(UserPayConfig userPayConfig, UserInfo userInfo, List<String> payWayCodeList) {
        //将写好的配置信息（商户号、支付产品、appKey、appSecret）通过邮件的方式发送给商户
        //准备MailProperties
        MailProperties prop = new MailProperties();
        prop.setId(NoUtil.getUUID());
        prop.setFrom(mailFrom);
        prop.setTo(new String[]{userInfo.getUserEmail()});
        prop.setSubject("商户支付配置访问网关系统参数");

        //正文
        StringBuilder builder = new StringBuilder();
        //邮件展示是通过html展示的 所以支持换行
        builder.append("商户号：").append(userInfo.getUserNo()).append("<br/>")
                .append("商户名称：").append(userInfo.getShopName()).append("<br/>")
                .append("支付产品的编号：").append(userPayConfig.getPayProductCode()).append("<br/>")
                .append("支付产品的名称：").append(userPayConfig.getPayProductName()).append("<br/>")
                .append("支付方式列表：").append(payWayCodeList.toString()).append("<br/>")
                .append("访问的appKey：").append(userPayConfig.getAppKey()).append("<br/>")
                .append("访问的appSecret ：").append(userPayConfig.getAppSecret()).append("<br/>");

        System.out.println("builder" + builder);

        prop.setText(builder.toString());

        NoticeUserPaymentEvent noticeEvent = new NoticeUserPaymentEvent(this, prop);

        //触发事件 监听事件
        applicationEventPublisher.publishEvent(noticeEvent);

    }

    @Override
    public List<UserPayInfo> queryPayInfo(String userNo, String productCode) {
        QueryWrapper<UserPayInfo> wrapper = new QueryWrapper<>();
        wrapper.eq("user_no", userNo)
                .eq("pay_product_code", productCode);
        return payInfoMapper.selectList(wrapper);
    }

    //删除主表及其相关的表
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void removePayInfoConfig(String userNo, String productCode) {
        //删除user_pay_config表
        int delete_user_pay_config = payConfigMapper.delete(new QueryWrapper<UserPayConfig>()
                .eq("user_no", userNo).eq("pay_product_code", productCode));
        if (delete_user_pay_config >= 1) {
            //删除user_pay_info表
            payInfoMapper.delete(new QueryWrapper<UserPayInfo>()
                    .eq("user_no", userNo)
                    .eq("pay_product_code", productCode));

        }
    }
}
